use crate::dto::*;
use crate::entity::*;
use crate::RB;
use hypers::prelude::{hypers_openapi, openapi, OpenApi, Responder, Response};
use rbatis::plugin::page::PageRequest;
use rbatis::rbdc::datetime::DateTime;

pub struct Role;

#[openapi(
    prefix = "/api",
    components(schemas(
        RoleListReq,
        RoleSaveReq,
        RoleUpdateReq,
        RoleDeleteReq,
        QueryRoleMenuReq,
        UpdateRoleMenuReq
    ))
)]
impl Role {
    #[post("role_list",tag = "查询角色列表",request_body = RoleListReq)]
    async fn role_list(item: RoleListReq) -> impl Responder {
        let role_name = item.role_name.unwrap_or_default();
        let status_id = item.status_id.unwrap_or_default();
        let page_req = &PageRequest::new(item.page_no, item.page_size);
        let result =
            SysRole::select_page_by_name(&mut RB.clone(), page_req, &role_name, &status_id).await;
        let mut res = Response::default();
        match result {
            Ok(page) => {
                let mut list_data: Vec<RoleListData> = Vec::new();
                for role in page.records {
                    list_data.push(RoleListData {
                        id: role.id.unwrap(),
                        sort: role.sort,
                        status_id: role.status_id,
                        role_name: role.role_name,
                        remark: role.remark.unwrap_or_default(),
                        create_time: role.create_time.unwrap().0.to_string(),
                        update_time: role.update_time.unwrap().0.to_string(),
                    })
                }
                res.json(&ok_result_page(list_data, page.total));
                res
            }
            Err(err) => {
                log::error!("{}", err.to_string());
                res.json(&err_result_page(err.to_string()));
                res
            }
        }
    }

    #[post("role_save",tag = "添加角色信息",request_body = RoleSaveReq)]
    async fn role_save(role: RoleSaveReq) -> impl Responder {
        log::info!("role_save params: {:?}", &role);
        let sys_role = SysRole {
            id: None,
            create_time: Some(DateTime::now()),
            update_time: Some(DateTime::now()),
            status_id: role.status_id,
            sort: role.sort,
            role_name: role.role_name,
            remark: role.remark,
        };
        let result = SysRole::insert(&mut RB.clone(), &sys_role).await;
        handle_result(result)
    }

    #[post("role_update",tag = "更新角色信息",request_body = RoleUpdateReq)]
    async fn role_update(role: RoleUpdateReq) -> impl Responder {
        log::info!("role_update params: {:?}", &role);

        let sys_role = SysRole {
            id: Some(role.id),
            create_time: None,
            update_time: Some(DateTime::now()),
            status_id: role.status_id,
            sort: role.sort,
            role_name: role.role_name,
            remark: role.remark,
        };
        let result = SysRole::update_by_column(&mut RB.clone(), &sys_role, "id").await;
        handle_result(result)
    }

    #[post("role_update",tag = "删除角色信息",request_body = RoleDeleteReq)]
    async fn role_delete(item: RoleDeleteReq) -> impl Responder {
        log::info!("role_delete params: {:?}", &item);
        let ids = item.ids;
        let user_role_list = SysUserRole::select_in_column(&mut RB.clone(), "role_id", &ids)
            .await
            .unwrap_or_default();
        let mut res = Response::default();
        if user_role_list.len() > 0 {
            res.json(&err_result_msg("角色已被使用,不能直接删除".to_string()));
            return res;
        }
        let result = SysRole::delete_in_column(&mut RB.clone(), "id", &ids).await;
        res.json(&handle_result(result));
        res
    }

    #[post("role_update",tag = "查询角色关联的菜单",request_body = QueryRoleMenuReq)]
    async fn query_role_menu(item: QueryRoleMenuReq) -> impl Responder {
        log::info!("query_role_menu params: {:?}", &item);

        // 查询所有菜单
        let menu_list = SysMenu::select_all(&mut RB.clone())
            .await
            .unwrap_or_default();

        let mut menu_data_list: Vec<MenuDataList> = Vec::new();
        let mut role_menu_ids: Vec<i32> = Vec::new();

        for y in menu_list {
            menu_data_list.push(MenuDataList {
                id: y.id.unwrap(),
                parent_id: y.parent_id,
                title: y.menu_name.clone(),
                key: y.id.unwrap().to_string(),
                label: y.menu_name.clone(),
                is_penultimate: y.parent_id == 2,
            });
            role_menu_ids.push(y.id.unwrap())
        }

        //不是超级管理员的时候,就要查询角色和菜单的关联
        if item.role_id != 1 {
            role_menu_ids.clear();
            let role_menu_list = query_menu_by_role(&mut RB.clone(), item.role_id)
                .await
                .unwrap_or_default();
            for x in role_menu_list {
                let m_id = x.get("menu_id").unwrap();
                role_menu_ids.push(*m_id)
            }
        }
        ok_result_data(QueryRoleMenuData {
            role_menus: role_menu_ids,
            menu_list: menu_data_list,
        })
    }

    #[post("update_role_menu",tag = "更新角色关联的菜单",request_body = UpdateRoleMenuReq)]
    async fn update_role_menu(item: UpdateRoleMenuReq) -> impl Responder {
        log::info!("update_role_menu params: {:?}", &item);
        let role_menu_result =
            SysRoleMenu::delete_by_column(&mut RB.clone(), "role_id", &item.role_id).await;

        let mut res = Response::default();
        match role_menu_result {
            Ok(_) => {
                let mut menu_role: Vec<SysRoleMenu> = Vec::new();
                for id in &item.menu_ids {
                    let menu_id = id.clone();
                    menu_role.push(SysRoleMenu {
                        id: None,
                        create_time: Some(DateTime::now()),
                        update_time: Some(DateTime::now()),
                        status_id: 1,
                        sort: 1,
                        menu_id,
                        role_id: item.role_id,
                    })
                }

                let result = SysRoleMenu::insert_batch(
                    &mut RB.clone(),
                    &menu_role,
                    item.menu_ids.len() as u64,
                )
                .await;
                res.json(&handle_result(result));
                res
            }
            Err(err) => {
                log::error!("{}", err.to_string());
                res.json(&err_result_msg(err.to_string()));
                res
            }
        }
    }
}
